import { pgTable, text, timestamp } from "drizzle-orm/pg-core";

export const usersTable = pgTable("user", {
  id: text("id").primaryKey(),
  name: text("name").notNull(),
  password: text("password"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at")
    .defaultNow()
    .$onUpdate(() => new Date())
    .notNull(),
});

export const sessionsTable = pgTable("session", {
  id: text("id").primaryKey(),
  accessTokenExpiresAt: timestamp("access_token_expires_at"),
  refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
  token: text("token").notNull().unique(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at")
    .defaultNow()
    .$onUpdate(() => new Date())
    .notNull(),
  userId: text("user_id")
    .notNull()
    .references(() => usersTable.id, { onDelete: "cascade" }),
});


import { createId } from "@paralleldrive/cuid2";
import { and, eq, gt } from "drizzle-orm";
import { Hono } from "hono";
import { sessionsTable, usersTable } from "../schemas/auth";
import { db } from "./db";

const SESSION_EXPIRES_MS = 7 * 24 * 60 * 60 * 1000;

// 初始化 Hono 应用
const app = new Hono();

// 类型定义
type SessionVariables = {
  session: typeof sessionsTable.$inferSelect;
  user: typeof usersTable.$inferSelect;
};

// 密码哈希函数
async function hashPassword(password: string): Promise<string> {
  const buffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(password));
  return Array.from(new Uint8Array(buffer))
    .map((byte) => byte.toString(16).padStart(2, "0"))
    .join("");
}

// 会话密钥哈希函数
async function hashSecretToHex(secret: string): Promise<string> {
  const buffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(secret));
  return Array.from(new Uint8Array(buffer))
    .map((byte) => byte.toString(16).padStart(2, "0"))
    .join("");
}

// 安全字符串比较
function constantTimeEqual(a: string, b: string): boolean {
  if (a.length !== b.length) return false;

  let result = 0;
  for (let i = 0; i < a.length; i++) {
    result |= a.charCodeAt(i) ^ b.charCodeAt(i);
  }
  return result === 0;
}

// 认证中间件
const authMiddleware = async (c: any, next: any) => {
  const sessionToken = c.req.header("Authorization")?.replace("Bearer ", "") || 
                       c.req.cookie("session");
  
  if (!sessionToken) {
    return c.json({ error: "未授权访问" }, 401);
  }

  const session = await validateSessionToken(sessionToken);
  if (!session) {
    return c.json({ error: "会话已过期" }, 401);
  }

  // 获取用户信息
  const [user] = await db
    .select()
    .from(usersTable)
    .where(eq(usersTable.id, session.userId));

  if (!user) {
    return c.json({ error: "用户不存在" }, 401);
  }

  // 将会话和用户信息存储在上下文中
  c.set("session", session);
  c.set("user", user);
  
  await next();
};

// 可选认证中间件（不强制要求认证）
const optionalAuthMiddleware = async (c: any, next: any) => {
  const sessionToken = c.req.header("Authorization")?.replace("Bearer ", "") || 
                       c.req.cookie("session");
  
  if (sessionToken) {
    const session = await validateSessionToken(sessionToken);
    if (session) {
      const [user] = await db
        .select()
        .from(usersTable)
        .where(eq(usersTable.id, session.userId));
      
      if (user) {
        c.set("session", session);
        c.set("user", user);
      }
    }
  }
  
  await next();
};

// 用户注册
export async function registerUser(name: string, password: string, idCard: string) {
  if (!process.env.AUTH_SECRET) {
    throw new Error("AUTH_SECRET environment variable is not set");
  }

  // 检查用户名是否已存在
  const [existingUser] = await db
    .select()
    .from(usersTable)
    .where(eq(usersTable.name, name));

  if (existingUser) {
    throw new Error("用户名已存在");
  }

  // 检查身份证是否已注册
  const [existingIdCard] = await db
    .select()
    .from(usersTable)
    .where(eq(usersTable.idCard, idCard));

  if (existingIdCard) {
    throw new Error("身份证号已注册");
  }

  // 创建用户
  const id = createId();
  const hashedPassword = await hashPassword(password);

  const [user] = await db
    .insert(usersTable)
    .values({
      id,
      name,
      password: hashedPassword,
      idCard
    })
    .returning();

  return user;
}

// 创建会话
export async function createSession(userId: string) {
  if (!process.env.AUTH_SECRET) {
    throw new Error("AUTH_SECRET environment variable is not set");
  }

  const id = createId();
  const secret = await hashSecretToHex(process.env.AUTH_SECRET);
  const token = `${id}.${secret}`;

  const [session] = await db.insert(sessionsTable).values({ id, userId, token }).returning();
  return session;
}

// 获取有效会话
async function getValidSession(sessionId: string) {
  const [session] = await db
    .select()
    .from(sessionsTable)
    .where(
      and(
        eq(sessionsTable.id, sessionId),
        gt(sessionsTable.createdAt, new Date(Date.now() - SESSION_EXPIRES_MS))
      )
    );

  return session ?? null;
}

// 验证会话令牌
export async function validateSessionToken(token: string) {
  if (!process.env.AUTH_SECRET) {
    throw new Error("AUTH_SECRET environment variable is not set");
  }

  const [sessionId, secretToVerify] = token.split(".", 2);
  if (!sessionId || !secretToVerify) return null;

  const [session, expectedSecret] = await Promise.all([
    getValidSession(sessionId),
    hashSecretToHex(process.env.AUTH_SECRET)
  ]);

  return session && constantTimeEqual(secretToVerify, expectedSecret) ? session : null;
}

// 删除会话
export async function deleteSession(sessionId: string): Promise<void> {
  await db.delete(sessionsTable).where(eq(sessionsTable.id, sessionId));
}

// 忘记密码 - 通过身份证验证
export async function forgotPassword(name: string, idCard: string, newPassword: string) {
  // 验证用户身份
  const [user] = await db
    .select()
    .from(usersTable)
    .where(
      and(
        eq(usersTable.name, name),
        eq(usersTable.idCard, idCard)
      )
    );

  if (!user) {
    throw new Error("用户名或身份证号不正确");
  }

  // 更新密码
  const hashedPassword = await hashPassword(newPassword);
  
  const [updatedUser] = await db
    .update(usersTable)
    .set({ password: hashedPassword })
    .where(eq(usersTable.id, user.id))
    .returning();

  return updatedUser;
}

// 用户登录
export async function loginUser(name: string, password: string) {
  // 查找用户
  const [user] = await db
    .select()
    .from(usersTable)
    .where(eq(usersTable.name, name));

  if (!user) {
    throw new Error("用户名或密码不正确");
  }

  // 验证密码
  const hashedPassword = await hashPassword(password);
  if (!constantTimeEqual(user.password, hashedPassword)) {
    throw new Error("用户名或密码不正确");
  }

  // 创建会话
  const session = await createSession(user.id);
  return { user, session };
}

// 用户退出登录
export async function logoutUser(token: string): Promise<void> {
  const session = await validateSessionToken(token);
  if (session) {
    await deleteSession(session.id);
  }
}

// Hono 路由

// 用户注册
app.post("/register", async (c) => {
  try {
    const { name, password, idCard } = await c.req.json();
    
    if (!name || !password || !idCard) {
      return c.json({ error: "请提供用户名、密码和身份证号" }, 400);
    }

    const user = await registerUser(name, password, idCard);
    return c.json({ message: "注册成功", user: { id: user.id, name: user.name } }, 201);
  } catch (error) {
    return c.json({ error: error.message }, 400);
  }
});

// 用户登录
app.post("/login", async (c) => {
  try {
    const { name, password } = await c.req.json();
    
    if (!name || !password) {
      return c.json({ error: "请提供用户名和密码" }, 400);
    }

    const { user, session } = await loginUser(name, password);
    
    // 设置会话 Cookie
    c.header("Set-Cookie", `session=${session.token}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${SESSION_EXPIRES_MS / 1000}`);
    
    return c.json({ 
      message: "登录成功", 
      user: { id: user.id, name: user.name },
      session: session.token 
    });
  } catch (error) {
    return c.json({ error: error.message }, 401);
  }
});

// 忘记密码
app.post("/forgot-password", async (c) => {
  try {
    const { name, idCard, newPassword } = await c.req.json();
    
    if (!name || !idCard || !newPassword) {
      return c.json({ error: "请提供用户名、身份证号和新密码" }, 400);
    }

    const user = await forgotPassword(name, idCard, newPassword);
    return c.json({ message: "密码重置成功", user: { id: user.id, name: user.name } });
  } catch (error) {
    return c.json({ error: error.message }, 400);
  }
});

// 退出登录
app.post("/logout", optionalAuthMiddleware, async (c) => {
  try {
    const sessionToken = c.req.header("Authorization")?.replace("Bearer ", "") || 
                         c.req.cookie("session");
    
    if (sessionToken) {
      await logoutUser(sessionToken);
      c.header("Set-Cookie", "session=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0");
    }
    
    return c.json({ message: "退出登录成功" });
  } catch (error) {
    return c.json({ error: error.message }, 400);
  }
});

// 获取当前用户信息
app.get("/me", authMiddleware, async (c) => {
  const user = c.get("user");
  
  return c.json({ 
    user: { 
      id: user.id, 
      name: user.name,
      createdAt: user.createdAt 
    } 
  });
});

// 更新用户信息
app.patch("/me", authMiddleware, async (c) => {
  try {
    const user = c.get("user");
    const updates = await c.req.json();
    
    // 过滤允许更新的字段
    const allowedUpdates = ["name"];
    const updateData: any = {};
    
    for (const key of allowedUpdates) {
      if (updates[key] !== undefined) {
        updateData[key] = updates[key];
      }
    }
    
    if (Object.keys(updateData).length === 0) {
      return c.json({ error: "没有有效的更新字段" }, 400);
    }
    
    const [updatedUser] = await db
      .update(usersTable)
      .set(updateData)
      .where(eq(usersTable.id, user.id))
      .returning();
    
    return c.json({ 
      message: "用户信息更新成功",
      user: { 
        id: updatedUser.id, 
        name: updatedUser.name,
        createdAt: updatedUser.createdAt 
      } 
    });
  } catch (error) {
    return c.json({ error: error.message }, 400);
  }
});

export default app;